package org.game.manager;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.xiaoleilu.hutool.util.MapUtil;
import org.apache.commons.collections4.MapUtils;
import org.base.BaseGoods;
import org.cache.GoodsCfgCache;
import org.cfg.EquipmentCfg;
import org.cfg.HeroCfg;
import org.cfg.ItemRecoverCfg;
import org.cfg.ItemTimeCfg;
import org.cfg.cache.DiscreteDataCfgCache;
import org.cfg.cache.ItemRecoverCfgCache;
import org.cfg.cache.LevelUpCfgCache;
import org.constant.DiscreteDataID;
import org.constant.EventConditionKey;
import org.constant.EventConditionType;
import org.constant.EventType;
import org.constant.ItemConstantId;
import org.constant.ItemType;
import org.constant.MailConstant;
import org.error.GameErrorCode;
import org.game.db.bean.Formation;
import org.game.db.bean.Hero;
import org.game.db.bean.Item;
import org.game.db.bean.Player;
import org.game.db.bean.PlayerData;
import org.game.db.bean.Role;
import org.game.db.cache.ItemCache;
import org.game.db.proxy.bean.PlayerProxy;
import org.game.db.vo.*;
import org.game.log.LogGoods;
import org.game.log.builder.LogDsp;
import org.game.log.dsp.GoodsDsp;
import org.game.module.itembo.ItemBO;
import org.game.msgBuilder.ItemMsgBuilder;
import org.game.plugin.event.GameEvent;
import org.game.plugin.event.GameEventPlugin;
import org.game.protobuf.s2c.S2CItemMsg.ItemList;
import org.game.protobuf.s2c.S2CShareMsg.ChangeType;
import org.game.protobuf.s2c.S2CShareMsg.RewardsMsg;
import org.game.util.ProtoUnit;
import org.utils.CommonUtil;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sojoys.artifact.constant.ArtifactErrorCode;
import com.sojoys.artifact.manager.MessageManager;
import com.sojoys.artifact.tools.ToolError;
import com.sojoys.artifact.tools.ToolMap;

/**
 * @author : DengYing
 * @CreateDate : 2017年8月16日 下午6:36:01
 * @Description ：物品管理器
 */
public class ItemManager {

	private ItemManager() {
	}

	private static ItemManager ME = new ItemManager();

	public static ItemManager me() {
		return ME;
	}
	
	
	/**
	 * 根据配置ID检查道具
	 * 
	 * @param goods
	 * @return
	 */
	public static boolean checkGoodsByCid(Player player, Map<Integer, Integer> goods) {
		if (MapUtils.isEmpty(goods))
			return true;
		replaceRechargeItemFirst(player,goods);
		for (Map.Entry<Integer, Integer> e : goods.entrySet()) {
			BaseGoods baseGoods = GoodsCfgCache.me().get(e.getKey());
			if (baseGoods == null) {
				return false;
			}
			
			BackpackVO backpackVO = player.getPlayerProxy().getBackpackByGoodsCid(e.getKey());
			if (backpackVO.countByCfg(baseGoods) < e.getValue()) {
				return false;
			}
		}
		return true;
	};
	
	
	/**
	 * 根据实例ID检查道具
	 * @param player
	 * @param goods
	 * @return
	 */
	public static boolean checkGoodsByDBId(Player player, Map<Long, Integer> goods) {
		if (MapUtils.isEmpty(goods))
			return true;
		
		for (Map.Entry<Long, Integer> e : goods.entrySet()) {
			Item item = ItemCache.me().getById(e.getKey());

			if (item == null ||item.getNum() < e.getValue()) {
				return false;
			}
		}
		return true;
	};
	
	/**
	 * 检查道具类型
	 * 
	 * @param goods
	 * @return
	 */
	public static boolean checkGoodsType(Map<Integer, Integer> goods, int superType, int subType, int smallType) {
		if (MapUtils.isEmpty(goods))
			return true;
		
		boolean bool = true;
		for (Entry<Integer, Integer> e : goods.entrySet()) {
			BaseGoods baseGoods = GoodsCfgCache.me().get(e.getKey());
			bool &= baseGoods.getSuperType() == superType;
			bool &= baseGoods.getSubType() == subType;
			bool &= baseGoods.getSmallType() == smallType;
		}
		return bool;
	}

	
	
	
	/**
	 * 检查背包空间
	 * @param player
	 * @param goods
	 * @return
	 */
	public static boolean checkBackpackSpace(Player player, Map<Integer, Integer> goods) {
		if (MapUtils.isEmpty(goods))
			return true;
		
		// 需要背包容量
		Map<Integer, Integer> needBackpackCapacity = new HashMap<>();
		PlayerProxy playerExt = player.getPlayerProxy();
		for (Map.Entry<Integer, Integer> e : goods.entrySet()) {
			BaseGoods baseGoods = GoodsCfgCache.me().get(e.getKey());
			BackpackVO backpackVO = playerExt.getBackpackByType(baseGoods.getBagType());
			if (baseGoods.getPileUp()) {
				Item item = backpackVO.getItem(e.getKey());
				if (item == null) {
					int needCapacity = ToolMap.getInt(baseGoods.getBagType(), needBackpackCapacity) + 1;
					needBackpackCapacity.put(baseGoods.getBagType(), needCapacity);					
				}else {
					int totalMax = baseGoods.getTotalMax();
					if(item.getNum() + e.getValue() > totalMax){
						return false;
					}
				}
			}else {
				int needCapacity = ToolMap.getInt(baseGoods.getBagType(), needBackpackCapacity) + e.getValue();
				needBackpackCapacity.put(baseGoods.getBagType(), needCapacity);
			}
		}
		// 检查需要的容量
		for (Entry<Integer, Integer> entry : needBackpackCapacity.entrySet()) {
			BackpackVO backpackVO = playerExt.getBackpackByType(entry.getKey());
			if (backpackVO.getFreeCapacity() < entry.getValue()) {
				return false;
			}
		}
		return true;
	}

	
	
	
	/**
	 * 添加道具 & 推送
	 * @param player
	 * @param hero
	 * @param role
	 * @param goods
	 */
	public static void addGoodsAndPush(Player player, Hero hero, Role role, Map<Integer, Integer> goods, LogDsp logDsp) {
		if (MapUtils.isEmpty(goods))
			return;
		ItemList.Builder itemChange = ItemList.newBuilder();
		addGoodsProxy(player, hero, role, itemChange, logDsp, goods);
		player.getPlayerProxy().sendMsg(MessageManager.me().create(ItemBO.getItems, ProtoUnit.toByte(itemChange.build())));
	}

	/**
	 * 添加道具 & 不推送
	 * @param player
	 * @param hero
	 * @param role
	 * @param itemChange
	 * @param goods
	 */
	public static void addGoods(Player player, Hero hero, Role role, ItemList.Builder itemChange, LogDsp logDsp, Map<Integer, Integer> goods) {
		ItemManager.addGoodsProxy(player, hero, role, itemChange, logDsp, goods);
	}
	
	/**
	 * 添加单个道具
	 */
	public static void addSingleGoods(Player player, Hero hero, Role role, ItemList.Builder itemChange, LogDsp logDsp, int goodsCid) {
		Map<Integer, Integer> drop = MapUtil.of(goodsCid, 1);
		ItemManager.addGoodsProxy(player, hero, role, itemChange, logDsp, drop);
	}

	/**
	 * 添加道具(代理)
	 * @param player
	 * @param hero
	 * @param role
	 * @param itemChange
	 */
	private static void addGoodsProxy(Player player, Hero hero, Role role, ItemList.Builder itemChange,LogDsp logDsp, Map<Integer, Integer> drops) {
		if (MapUtils.isEmpty(drops))
			return;
		
		
		
		// 转换策略
		Map<Integer, Integer> convertStrategy = Maps.newHashMap();
		// 邮件策略
		Map<Integer, Integer> mailStrategy = Maps.newHashMap();

		PlayerProxy playerExt = player.getPlayerProxy();

		Map<Integer,Integer> changedInfo = Maps.newHashMap();

		drops.forEach((id,num) -> {
			
			BaseGoods baseGoods = GoodsCfgCache.me().get(id);
			// 取得背包
			BackpackVO backpackVO = playerExt.getBackpackByType(baseGoods.getBagType());
			// 取得能够叠加的物品
			Item item = baseGoods.getPileUp() ? backpackVO.getItem(id) : null;
			// 是否具有转换策略
			boolean isConvert = baseGoods.isConvert();
			// 空闲空间
			int freeCapacity = backpackVO.getFreeCapacity();
			// 最大数量
			int totalMax = baseGoods.getTotalMax();
			// 溢出数量
			int overflowNum = 0;
			if(item != null){
				overflowNum = item.getNum() + num - totalMax;
			}else{ 
				if (baseGoods instanceof HeroCfg) {
					// 如果英雄存在全部溢出
					boolean exist = player.getPlayerProxy().getHerosByCid().containsKey(baseGoods.getId());
					if (exist) {
						overflowNum = num;
					} else{
						overflowNum = num - 1;
					}
				}else {
					overflowNum = backpackVO.countByCfg(baseGoods) + num - totalMax;					
				}
			}
			// 上限溢出策略
			if (overflowNum > 0) {
				if (isConvert) {
					for (int i = 0; i < overflowNum; i++) {
						CommonUtil.changeMap(convertStrategy, baseGoods.getConvertMax());						
					}
				}else {
					CommonUtil.changeMap(mailStrategy, id, overflowNum);	
				}
				// 重置添加数量
				num -= overflowNum;
			}
			// 爆仓库策略
			if (item == null) {
				if (baseGoods.getPileUp()) {
					if (freeCapacity < 1) {
						CommonUtil.changeMap(mailStrategy, id, num);
						// 重置添加数量
						num = 0;					
					}
				}else {
					if (freeCapacity < num) {
						CommonUtil.changeMap(mailStrategy, id, num - freeCapacity);
						// 重置添加数量
						num = freeCapacity;						
					}
				}
			}
			
			if (num < 1) {
				return;
			}

			// 获得事件 为什么在这里调用原因不明，先已经移到下面去了
//			obtainEvent(player, hero, role, num, baseGoods,backpackVO,logDsp.getDsp());
			
			
			if (baseGoods instanceof HeroCfg) {
				// 添加英雄
				for (int i = 0; i < num; i++) {
					HeroManager.me().addHero(player, (HeroCfg) baseGoods,logDsp);
				}
			} else {
				switch (id) {
				case ItemConstantId.PLAYER_EXP:
					int actualAddExp = PlayerManager.me().addExp(player, num);
					changedInfo.put(id,actualAddExp);
					break;
				case ItemConstantId.HERO_EXP:
					// 如果没有指定英雄，就加上阵全部英雄
					if (hero == null) {
						HeroManager.me().addTeamExp(player, num);
					} else {
						HeroManager.me().addExp(num, hero);
					}
					break;
				case ItemConstantId.ROLE_FAVOR:{
					// 如果没有指定精灵，就加当前使用精灵
					Role _role = role == null ? playerExt.getCurrentRole() : role;
					RoleManager.me().changeFavor(_role, num ,logDsp.clone());
				}
					break;
				case ItemConstantId.FORMATION_FAVOR:{
					Formation formation = playerExt.getCurrentFormation();
					Set<Role> roles = formation.getFormationProxy().getRoles();
					for (Role role1 : roles) {
						RoleManager.me().changeFavor(role1, num ,logDsp.clone());
					}
				}
					break;
				case ItemConstantId.ROLE_MOOD:{
					// 如果没有指定精灵，就加当前使用精灵
					Role _role = role == null ? playerExt.getCurrentRole() : role;
					RoleManager.me().changeMood(_role, num ,logDsp.clone());
					break;
				}
				default:
					if (item == null) {
						if (baseGoods.getPileUp() || baseGoods instanceof ItemTimeCfg) {
							item = createGoodsProxy(baseGoods, num, player, hero, role,logDsp);
							ItemMsgBuilder.addItemMsg(itemChange, player, ChangeType.ADD, item);
							backpackVO.addItem(item);
						}else {
							for (int i = 0; i < num; i++) {
								item = createGoodsProxy(baseGoods, 1, player, hero, role , logDsp);
								ItemMsgBuilder.addItemMsg(itemChange, player, ChangeType.ADD, item);
								backpackVO.addItem(item);
							}
						}
					} else {
//						item.setNum(item.getNum() + dropItem.getNum());
						backpackVO.changeCount(item, num);
//						item.update();
						ItemMsgBuilder.addItemMsg(itemChange, player, ChangeType.UPDATE, item);
					}
					
					checkAutoRecover(player, baseGoods, backpackVO);

					LogGoods.me().log(player.getId(), id, num, backpackVO.countByCfg(item.getCid()), logDsp.clone());
					
					if(baseGoods instanceof ItemTimeCfg){
						player.getPlayerProxy().startSecondsJob();
					}
					break;
				}
			}

			obtainEvent(player, hero, role, num, baseGoods,backpackVO,logDsp.getDsp());

			if (ElementCollectManager.checkItemType(baseGoods.getSuperType())){
				ElementCollectManager.recordElement(player, baseGoods.getSuperType(), baseGoods.getId());
			}
			
		});

		drops.putAll(changedInfo);

		if (!convertStrategy.isEmpty()) {
			// 添加转换备注
			addGoodsProxy(player, hero, role, itemChange, logDsp.clone().addCourse("convert"), convertStrategy);
		}

		if (!mailStrategy.isEmpty()) {
			// 添加溢出备注
			MailManager.me().sendPersonalMail(0, player.getId(), MailConstant.TEXT_TYPE_CONFIG, "mail.overflow.title", "mail.overflow.content", null, mailStrategy, logDsp);
		}
	}


	private static void obtainEvent(Player player, Hero hero, Role role, Integer num, BaseGoods baseGoods,BackpackVO backpackVO,int dspCode) {
		Map<String, Object> in = Maps.newHashMap();
		in.put("onHeroId", hero == null ? 0 : hero.getCid());
		in.put("onRoleId", role == null ? 0 : role.getCid());
		if (baseGoods instanceof HeroCfg) {
			in.put(EventConditionKey.CONDITION_TYPE, EventConditionType.HOLD_HERO);
			in.put(EventConditionKey.HERO_CID, baseGoods.getId());
			in.put(EventConditionKey.QUALITY, baseGoods.getQuality());
		}else {
			in.put(EventConditionKey.CONDITION_TYPE, EventConditionType.ADD_ITEM);
			in.put(EventConditionKey.ITEM_CID, baseGoods.getId());
			in.put(EventConditionKey.SUPER_TYPE, baseGoods.getSuperType());
			in.put(EventConditionKey.SUB_TYPE, baseGoods.getSubType());
			in.put(EventConditionKey.SMALL_TYPE, baseGoods.getSmallType());
			in.put(EventConditionKey.COUNT, num);
            in.put(EventConditionKey.EXCLUDE, dspCode);
		}
		GameEvent event = new GameEvent(player, EventType.ITEM_EVENT, in);
		GameEventPlugin.syncSubmit(event);
	}

	/**
	 * 检查自动恢复
	 * @param player
	 * @param baseGoods
	 * @param backpackVO
	 */
	public static void checkAutoRecover(Player player, BaseGoods baseGoods, BackpackVO backpackVO) {
		ItemRecoverCfg itemRecoverCfg = ItemRecoverCfgCache.me().getByItemId(baseGoods.getId());
		if (itemRecoverCfg != null) {
			// 取得最大恢复数量
			int max_count = getMaxAutoRecoverCount(player, itemRecoverCfg);
			PlayerData playerData = player.getPlayerDatasFkPlayerId();
			Map autoRecover = playerData.getPlayerDataProxy().getAutoRecover();

			// 检查该道具是否在恢复队列中
			boolean start = autoRecover.containsKey(itemRecoverCfg.getItemId());
			if (start) {
				// 如果已经在恢复队里中，查看是否已经超过最大数量，如果超出最大恢复的数量。则停止恢复
				if (backpackVO.countByCfg(baseGoods) >= max_count) {
					autoRecover.remove(baseGoods.getId());
					playerData.update();
				}
			}else {
				// 如果不在恢复队列中，查看是否低于最大恢复数量，如果低于最大恢复数量。则开启恢复
				if (backpackVO.countByCfg(baseGoods) < max_count) {
					autoRecover.put(baseGoods.getId(), System.currentTimeMillis());
					playerData.update();
				}
			}
			player.getPlayerProxy().startSecondsJob();
		}
	}

	/**
	 * 取得最大恢复次数
	 * @param player
	 * @param itemRecoverCfg
	 * @return
	 */
	public static int getMaxAutoRecoverCount(Player player, ItemRecoverCfg itemRecoverCfg) {
		int max_count;
		switch (itemRecoverCfg.getItemId()) {
		case ItemConstantId.AP:
			max_count = LevelUpCfgCache.me().getById(player.getLevel()).getMaxEnergy();
			break;
		default:
			max_count = itemRecoverCfg.getMaxRecoverCount();
			break;
		}
		return max_count;
	}
	
	
	
	/**
	 * 根据配置ID除物品,默认先扣除最近到期道具
	 */
	public static boolean costGoodsByCid(Player player, Map<Integer, Integer> goods,LogDsp logDsp,ItemList.Builder builder) {
		if (MapUtils.isEmpty(goods))
			return false;
		// 扣除道具之前必须验证道具是否足够
		ToolError.isAndTrue(GameErrorCode.ITEM_NOT_ENOUGH, "道具不足", !checkGoodsByCid(player, goods));
		PlayerProxy playerExt = player.getPlayerProxy();
		for (Map.Entry<Integer, Integer> e : goods.entrySet()) {
			BackpackVO backpackVO = playerExt.getBackpackByGoodsCid(e.getKey());
			// 总共需要扣除数量
			int costSumCount = e.getValue();
			
			// 检查是否有时限道具
			Set<String> childIds = backpackVO.getChildIds(e.getKey());
			if (childIds!=null) {
				for (String childId : childIds) {
					String[] strs = childId.split("-");
					int cid = Integer.valueOf(strs[1]);
					Item item = backpackVO.getItem(cid);
					// 扣除当前实例数量
					int costCount = Math.max(0, Math.min(costSumCount, item.getNum()));
					costItem(player, logDsp, builder, costCount, item,backpackVO);
					costSumCount -=costCount;
					if (costSumCount <= 0) {
						break;
					}
				}
			}
			// 限时道具不足，扣除道具本身实例
			if (costSumCount > 0) {
				Item item = backpackVO.getItem(e.getKey());
				costItem(player, logDsp, builder,costSumCount, item,backpackVO);
			}
		}
		
		if (builder!=null) {
			playerExt.sendMsg(MessageManager.me().create(ItemBO.getItems, ProtoUnit.toByte(builder.build())));
		}
		return true;
	}
	
	
	/**
	 * 根据配置ID除物品,默认先扣除最近到期道具
	 */
	public static boolean costGoodsByCid(Player player, int[] cids,int[] nums,LogDsp logDsp,ItemList.Builder builder) {
		ToolError.isAndTrue(ArtifactErrorCode.PARAM_ERROR, "参数错误", (cids==null || nums==null ||cids.length!=nums.length));
		Map<Integer, Integer> goods = Maps.newHashMap();
		for (int i = 0; i < nums.length; i++) {
			int newNum = ToolMap.getInt(cids[i], goods, 0) + nums[i];
			goods.put(cids[i], newNum);
		}
		return costGoodsByCid(player, goods, logDsp, builder);
	}
	
	
	
	/**
	 * 根据实例ID (只能扣除不叠加的道具)
	 */
	public static boolean costGoodsByDBId(Player player, Map<Long, Integer> goods,LogDsp logDsp,ItemList.Builder builder) {
		if (MapUtils.isEmpty(goods))
			return false;
		
		// 扣除道具之前必须验证道具是否足够
		ToolError.isAndTrue(GameErrorCode.ITEM_NOT_ENOUGH, "道具不足", !checkGoodsByDBId(player, goods));
		
		PlayerProxy playerExt = player.getPlayerProxy();
		
		for (Map.Entry<Long, Integer> e : goods.entrySet()) {
			Item item = ItemCache.me().getById(e.getKey());
			ToolError.isAndTrue(ArtifactErrorCode.PARAM_ERROR,"道具id异常，非本人道具", item.getPlayerId()!=player.getId());
			int changeCount = e.getValue();
			
			BaseGoods baseGoods = GoodsCfgCache.me().get(item.getCid());
			// 取得背包
			BackpackVO backpackVO = playerExt.getBackpackByType(baseGoods.getBagType());
			
			costItem(player,logDsp, builder,changeCount, item,backpackVO);
		}
		
		if (builder!=null) {
			playerExt.sendMsg(MessageManager.me().create(ItemBO.getItems, ProtoUnit.toByte(builder.build())));
		}
		return true;
	}
	
	/**
	 * 根据实例ID (只能扣除不叠加的道具)
	 */
	public static boolean costGoodsById(Player player, Long[] ids,Integer[] nums, LogDsp logDsp,ItemList.Builder builder) {
		ToolError.isAndTrue(ArtifactErrorCode.PARAM_ERROR, "参数错误", ids==null || nums==null ||ids.length!=nums.length);
		Map<Long, Integer> goods = Maps.newHashMap();
		for (int i = 0; i < nums.length; i++) {
			int newNum = ToolMap.getInt(ids[i], goods , 0) + nums[i];
			goods.put(ids[i], newNum);
		}
		return costGoodsByDBId(player, goods, logDsp, builder);
	}
	
	/**
	 * 真实的扣除物品操作
	 */
	private static void costItem(Player player, LogDsp logDsp, ItemList.Builder builder,int costCount, Item item,BackpackVO backpackVO) {
		
		
		int nowCount = item.getNum();
		
		BaseGoods baseGoods = GoodsCfgCache.me().get(item.getCid());
		
		ToolError.isAndTrue(GameErrorCode.ITEM_NOT_ENOUGH, "道具不足", nowCount < costCount);

		// 触发获得事件
		Map<String, Object> in = Maps.newHashMap();
		in.put(EventConditionKey.CONDITION_TYPE, EventConditionType.DEL_ITEM);
		in.put(EventConditionKey.ITEM_CID, item.getCid());
		in.put(EventConditionKey.COUNT, costCount);
		in.put(EventConditionKey.EXCLUDE, logDsp.getDsp());
		GameEvent event = new GameEvent(player, EventType.ITEM_EVENT, in);
		GameEventPlugin.syncSubmit(event);
				
		// 剩余数量
		int lastCount = nowCount - costCount;
		
		if (lastCount > 0) {
			backpackVO.changeCount(item, -costCount);
//			item.setNum(lastCount);
//			item.update();
			if (builder != null) {
				ItemMsgBuilder.packageItemInfo(ChangeType.UPDATE,builder,item);
			}
		} else {
			backpackVO.changeCount(item, -nowCount);
//			item.setNum(0);
//			item.delete();
			
			// 从背包中删除
//			player.getBackpackByType(baseGoods.getBagType()).removeGoods(item);
			backpackVO.removeGoods(item);
			if (builder != null) {
				ItemMsgBuilder.packageItemInfo(ChangeType.DELETE,builder,item);
			}
		}
		checkAutoRecover(player, baseGoods, backpackVO);
		// 日志记录
		LogGoods.me().log(player.getId(), item.getCid(), -costCount, item.getNum(), logDsp);
	}

	
	/**
	 * 根据配置ID使用道具</br>
	 * 先扣除、在添加使用效果</br>
	 */
	public static List<RewardsMsg> useGoodsByCid(Player player, Hero hero, Role role, Map<Integer, Integer> goods,List<Integer> customParame,LogDsp logDsp) {
		
		// 使用消耗
		Map<Integer, Integer> useCast = new HashMap<>();
					
		for (Entry<Integer, Integer> integer : goods.entrySet()) {
			BaseGoods baseGoods = GoodsCfgCache.me().get(integer.getKey());
			
			Map<Integer, Integer> itemUseCast = baseGoods.getUseCast();
			if(!itemUseCast.isEmpty()){
				for (Entry<Integer, Integer> e : itemUseCast.entrySet()) {
					int castCount = ToolMap.getInt(e.getKey(), useCast , 0 ) + e.getValue();
					useCast.put(e.getKey(), castCount);
				}
			}
		}
		
		ItemList.Builder builder = ItemList.newBuilder();
		
		if (!useCast.isEmpty()) {
			// 扣除使用消耗
			costGoodsByCid(player, useCast,logDsp, builder);			
		}
				
		costGoodsByCid(player, goods, logDsp ,ItemList.newBuilder());
		
		List<RewardsMsg> rewards = unpackNotify(player, hero, role,customParame,true, goods, logDsp);
		
		return rewards;
	}
	
	
	/**
	 * 根据实例ID使用道具</br>
	 * 先扣除、在添加使用效果</br>
	 */
	public static List<RewardsMsg> useGoodsByDbId(Player player, Hero hero, Role role, Map<Long, Integer> goods,List<Integer> customParame,LogDsp logDsp) {
		
		Map<Integer, Integer> useGoods = new HashMap<>(goods.size());
		// 使用消耗
		Map<Integer, Integer> useCast = new HashMap<>(goods.size());
		
		for (Entry<Long, Integer> integer : goods.entrySet()) {
			Item item = ItemCache.me().getById(integer.getKey());
			
			
			Map<Integer, Integer> itemUseCast = item.getItemProxy().getCfg().getUseCast();
			if(!itemUseCast.isEmpty()){
				for (Entry<Integer, Integer> e : itemUseCast.entrySet()) {
					int castCount = ToolMap.getInt(e.getKey(), useCast , 0 ) + e.getValue();
					useCast.put(e.getKey(), castCount);
				}
			}
			
			
			int count = ToolMap.getInt(item.getCid(), useGoods , 0 ) + integer.getValue();
			useGoods.put(item.getCid(), count);
		}
		
		ItemList.Builder builder = ItemList.newBuilder();
		
		if (!useCast.isEmpty()) {
			// 扣除使用消耗
			costGoodsByCid(player, useCast, logDsp, builder);			
		}

		
		costGoodsByDBId(player, goods, logDsp,builder);
		
		List<RewardsMsg> rewards = unpackNotify(player, hero, role,customParame,true, useGoods, logDsp);
		return rewards;
	}
	
	
	/**
	 * 解包 & 封装奖励信息
	 */
	public static List<RewardsMsg> unpackNotify(Player player, Map<Integer, Integer> drops,LogDsp logDsp) {
		return unpackNotify(player, null, null,null, false, drops,logDsp);
	}

	/**
	 * 解包 & 封装奖励信息
	 */
	public static List<RewardsMsg> unpackNotify(Player player, Hero hero, Role role, Map<Integer, Integer> drops,LogDsp logDsp) {
		return unpackNotify(player, hero, role,null, false, drops,logDsp);
	}
	
	/**
	 * 解包 & 封装奖励信息
	 */
	private static List<RewardsMsg> unpackNotify(Player player, Hero hero, Role role,List<Integer> customParame, boolean use ,Map<Integer, Integer> drops,LogDsp logDsp) {
		if (MapUtils.isEmpty(drops))
			drops = Maps.newHashMap();

		Map<Integer, Integer> out = Maps.newLinkedHashMap();
		for (Entry<Integer, Integer> item : drops.entrySet()) {
			int id = item.getKey();
			int num = item.getValue();
			if (id == 0 || num == 0)
				continue;
			
			BaseGoods cfg = GoodsCfgCache.me().get(id);
			if ((!use && cfg.getAutoUse()) || use) {
				for (int i = 0; i < num; i++) {
					ItemPackageHelper.unpack(cfg.getUseProfit(), customParame, out);
				}
			}else {
				CommonUtil.changeMap(out, id, num);
			}
		}
		
		// 添加道具
		ItemList.Builder itemChange = ItemList.newBuilder();
		addGoodsProxy(player, hero, role, itemChange,logDsp, out);
					
		// 封装掉落信息
		List<RewardsMsg> rewards = Lists.newArrayList();
		
		out.forEach((k,v) -> {
			rewards.add(RewardsMsg.newBuilder().setId(k).setNum(v).build());
		});
		player.getPlayerProxy().sendMsg(MessageManager.me().create(ItemBO.getItems, ProtoUnit.toByte(itemChange.build())));
		return rewards;
	}
	

	/**
	 * 创建道具代理
	 */
	private static Item createGoodsProxy(BaseGoods cfg, int num, Player player, Hero hero, Role role,LogDsp logDsp) {
		Item item = createItemProxy(cfg, num, player.getId());
		item.insert();

		// 创建时装 
		if (item instanceof DressVO) {
			// 只有精灵激活获得才立马穿戴
			if (role != null && logDsp.getDsp() == GoodsDsp.ACTIVATE_ROLE.getCode()) {
				DressVO vo = (DressVO) item;
				vo.setRoleId(role.getId());
				role.getRoleProxy().setDressVO(vo);				
			}
		}
		// 创建灵装
		if (item instanceof EquipmentVO){
			EquipmentVO vo = (EquipmentVO) item;
			EquipmentManager.me().initEquipment(vo, (EquipmentCfg) cfg);
		}

		//皮肤
		if (item instanceof SkinVO){
			// 只有活动英雄的时候才立马装备
			if (hero != null && logDsp.getDsp() == GoodsDsp.GAIN_HERO.getCode()){
				SkinVO skin = (SkinVO) item;
				HeroManager.me().changeHeroSkin(hero,skin,null);
			}
		}

		item.update();
		return item;
	}

	/**
	 * 创建物品代理
	 */
	public static Item createItemProxy(BaseGoods cfg, int num, int pid) {
		Item item;
		switch (cfg.getSuperType()) {
		case ItemType.DRESS:
			item = new DressVO(0L, num, cfg.getId(), Maps.newHashMap(), pid);
			break;
		case ItemType.EQUIP:
			item = new EquipmentVO(0L, num, cfg.getId(), Maps.newHashMap(), pid);
			break;
		case ItemType.SKIN:
			item = new SkinVO(0L, num, cfg.getId(), Maps.newHashMap(), pid);
			break;
		case ItemType.ROOM:
			item = new RoomVO(0L, num, cfg.getId(), Maps.newHashMap(), pid);
			break;
		default:
			item = new Item(0L, num, cfg.getId(), Maps.newHashMap(), pid);
			break;
		}
		return item;
	}

	
    /**
     * 用充值资源替换赠送资源，优先使用充值资源
     */
    private static Map replaceRechargeItemFirst(Player player, Map<Integer, Integer> costMap){
        Map<Integer,Integer> priorityCostIdMapping = DiscreteDataCfgCache.me().getData(DiscreteDataID.PRIORITY_COST_ITEM);
        priorityCostIdMapping.forEach((costCid,priorityCid)->{
            //1.没有被替换资源，退出
            if (!costMap.containsKey(costCid)){
                return;
            }
            //2.已经有充值资源，说明已经替换过，退出
            if (costMap.containsKey(priorityCid)){
                return;
            }
            int rechargeNum = player.getPlayerProxy().getGoodsNumByCid(priorityCid);
            if (rechargeNum == 0){
                return;
            }

            int costNum = costMap.get(costCid);
            if (rechargeNum >= costNum){
                costMap.remove(costCid);
                costMap.put(priorityCid,costNum);
            }else{
                costMap.put(priorityCid,rechargeNum);
                costMap.put(costCid,costNum - rechargeNum);
            }
        });
        return costMap;
    }
}